﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Assignment3
{
    public class Camera
    {
        public Matrix view;
        public Matrix proj;
        public float Zoom = 0;


        public Vector3 avatarPosition = new Vector3(0,0,10);
        public float avatarYaw;
        float avatarPitch;

        public Vector3 velocity = new Vector3(0f,0f,0f);

        // direction of the camera
        Vector3 cameraReference = new Vector3(0, 0, 1);

        public Vector3 lookat = new Vector3(0f,0f,0f);

        // Set rates in world units per 1/60th second (the default fixed-step interval).
        float rotationSpeed = 4f / 60f;
        float forwardSpeed = 25f / 60f;

        // Set field of view of the camera in radians (pi/4 is 45 degrees).
        static float viewAngle = MathHelper.PiOver4;

        // Set distance from the camera of the near and far clipping planes.
        static float nearClip = 1.0f;
        static float farClip = 2000.0f;

        GraphicsDeviceManager graphics;

        public Camera(GraphicsDeviceManager gdm)
        {
            this.graphics = gdm;
        }

        public Camera(GraphicsDeviceManager gdm, Vector3 avatarPos, Vector3 camReference)
        {
            this.graphics = gdm;
            this.avatarPosition = avatarPos;
            this.cameraReference = camReference;
        }

        public void ResetCamera()
        {
            avatarPosition = new Vector3(-2.5f, 0, -4f);
            avatarYaw = -1.5f;

        }

        /// <summary>
        /// Updates the position and direction of the camera relative to the avatar.
        /// </summary>
        public void UpdateCamera()
        {
            // Calculate the camera's current position.
            Vector3 cameraPosition = avatarPosition;

            Matrix rotationMatrix = Matrix.CreateRotationX(avatarPitch) * Matrix.CreateRotationY(avatarYaw) ;
      
            // Create a vector pointing the direction the camera is facing.
            Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);

            // Calculate the position the camera is looking at.
            Vector3 cameraLookat = cameraPosition + transformedReference;
            lookat = cameraLookat;
            // Set up the view matrix and projection matrix.
            view = Matrix.CreateLookAt(cameraPosition, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));

            Viewport viewport = graphics.GraphicsDevice.Viewport;
            float aspectRatio = (float)viewport.Width / (float)viewport.Height;



            proj = Matrix.CreatePerspectiveFieldOfView(viewAngle + MathHelper.ToRadians(Zoom), aspectRatio, nearClip, farClip);
            
        }

        /// <summary>
        /// Updates the position and direction of the avatar.
        /// </summary>
        public void HandleInput(Maze maze)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);

            Vector3 lastValidPosition = avatarPosition;

            if (keyboardState.IsKeyDown(Keys.Left) || gamepadState.ThumbSticks.Right.X < 0)
            {
                // Rotate left.
                avatarYaw += rotationSpeed;
            }
            if (keyboardState.IsKeyDown(Keys.Right) || gamepadState.ThumbSticks.Right.X > 0)
            {
                // Rotate right.
                avatarYaw -= rotationSpeed;
            }

            if (keyboardState.IsKeyDown(Keys.Up) || gamepadState.ThumbSticks.Right.Y > 0)
            {
                // Rotate left.
                avatarPitch -= rotationSpeed;
            }
            if (keyboardState.IsKeyDown(Keys.Down) || gamepadState.ThumbSticks.Right.Y < 0)
            {
                // Rotate right.
                avatarPitch += rotationSpeed;
            }

            if (keyboardState.IsKeyDown(Keys.W) || gamepadState.ThumbSticks.Left.Y > 0)
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                velocity = new Vector3(0, 0, forwardSpeed);
                velocity = Vector3.Transform(velocity, forwardMovement);
                avatarPosition.Z += velocity.Z;
                avatarPosition.X += velocity.X;
            }
            if (keyboardState.IsKeyDown(Keys.S) || gamepadState.ThumbSticks.Left.Y < 0)
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                velocity = new Vector3(0, 0, -forwardSpeed);
                velocity = Vector3.Transform(velocity, forwardMovement);
                avatarPosition.Z += velocity.Z;
                avatarPosition.X += velocity.X;
            }

            if (keyboardState.IsKeyDown(Keys.A) || gamepadState.ThumbSticks.Left.X < 0)
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                velocity = new Vector3(forwardSpeed, 0,0 );
                velocity = Vector3.Transform(velocity, forwardMovement);
                avatarPosition.Z += velocity.Z;
                avatarPosition.X += velocity.X;
            }
            if (keyboardState.IsKeyDown(Keys.D) || gamepadState.ThumbSticks.Left.X > 0)
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                velocity = new Vector3(-forwardSpeed, 0, 0);
                velocity = Vector3.Transform(velocity, forwardMovement);
                avatarPosition.Z += velocity.Z;
                avatarPosition.X += velocity.X;
            }

            if (keyboardState.IsKeyDown(Keys.PageUp) || gamepadState.IsButtonDown(Buttons.DPadUp))
            {
                Zoom += .5f;
            }
            if (keyboardState.IsKeyDown(Keys.PageDown) || gamepadState.IsButtonDown(Buttons.DPadDown))
            {
                Zoom -= .5f;
            }

            maze.HandleCollisions(ref avatarPosition, lastValidPosition);
        }
    }
}
